﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Data.SqlClient;
using System.ComponentModel;
using System.Collections;
using System.Windows.Threading;
using System.IO;

namespace SoundServant.Controls
{
    /// <summary>
    /// Interaction logic for Browser.xaml
    /// </summary>
    public partial class BrowserControl : UserControl
    {
        SqlConnection dbConnection;
        int? tickTock = null;
        int numRecordings;
        long sizeOfRecordings;
        Congregation congregation;
        Recorder jane;
        Burner max;
        BackgroundWorker resultsWorker;
        BackgroundWorker numRecordingsWorker;
        int page = 0;
        bool reSearch = false;
        bool displayingResults = false;
        ArrayList results = new ArrayList();
        ResultControl selectedResult;
        StoredRecording selectedRecording;
        private delegate void DisplayPageInvokeHandler(int page);

        public BrowserControl(Congregation c, Recorder j, Burner m)
        {
            InitializeComponent();

            jane = j;
            max = m;
            congregation = c;

            Library.LibraryRecordingDeleted += new Library.LibraryRecordingDeletedEventHandler(Library_LibraryRecordingDeleted);
            Library.RecordingsUpdated += new Library.VoidEventHandler(Library_RecordingsUpdated);

            resultsWorker = new BackgroundWorker();
            resultsWorker.DoWork += new DoWorkEventHandler(resultsWoker_DoWork);
            resultsWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(resultsWoker_RunWorkerCompleted);

            numRecordingsWorker = new BackgroundWorker();
            numRecordingsWorker.DoWork += new DoWorkEventHandler(numRecordingsWorker_DoWork);
            numRecordingsWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(numRecordingsWorker_RunWorkerCompleted);

            if (!numRecordingsWorker.IsBusy)
            {
                numRecordingsWorker.RunWorkerAsync();
            }

            dbConnection = SS.Connection();
        }

        void numRecordingsWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            StatusLabel.Content = numRecordings + " Recordings (" + (sizeOfRecordings / (long)1048576) + " Mb)";
            Logs.Information("Browser", "Number of Recordings: " + numRecordings + " Size of Recordings: " + (sizeOfRecordings / 1048576));
        }

        void numRecordingsWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            Logs.Information("Browser", "Updating number and size of recordings");
            SqlConnection connection = SS.Connection();

            SqlCommand command = new SqlCommand("SELECT recId FROM recordings WHERE recCong = " + congregation.Id, connection);
            SqlDataReader dataReader = command.ExecuteReader();

            numRecordings = 0;
            sizeOfRecordings = 0;

            while (dataReader.Read())
            {
                DirectoryInfo directoryInfo = new DirectoryInfo(Options.Default.BaseDirectory + "\\" + Options.Default.RecordDirectory + "\\" + dataReader[0]);
                numRecordings++;
                sizeOfRecordings += SS.DirectorySize(directoryInfo);
            }

            dataReader.Close();
            connection.Close();
        }

        void Library_RecordingsUpdated()
        {
            Search();
            if (!numRecordingsWorker.IsBusy)
            {
                numRecordingsWorker.RunWorkerAsync();
            }
        }


        void resultsWoker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (reSearch)
            {
                reSearch = false;
                Search();
            }
            else
            {
                displayingResults = true;
                DisplayResults(page);
                displayingResults = false;
            }
        }

        void resultsWoker_DoWork(object sender, DoWorkEventArgs e)
        {
            // Construct SQL for search Query
            string searchForText = SS.MakeSQLSafe((string)e.Argument);
            string sql;
            sql = "SELECT recordings.recId, recordings.recDate, recordings.recTitle, recordings.recType, recordings.recType AS Expr1, tracks.trackTitle, discs.discID, tracks.trackID, discs.discTitle FROM congregations RIGHT OUTER JOIN recordings RIGHT OUTER JOIN tracks LEFT OUTER JOIN discs ON tracks.trackDisc = discs.discID ON recordings.recId = tracks.trackRec ON congregations.congId = recordings.recCong";
            sql += " WHERE recCong = " + congregation.Id;
            if (searchForText != "" && searchForText != "[Search Criteria]") sql += " AND ( recordings.recTitle LIKE '%" + searchForText + "%' OR discs.discTitle LIKE '%" + searchForText + "%' OR tracks.trackTitle LIKE '%" + searchForText + "%')";
            // if (MeetingTypeComboBox.SelectedMeetingType) sql += " AND recType = " + (int)MeetingTypeComboBox.SelectedMeetingType;
            sql += " ORDER BY recId DESC";
            Logs.Information("Browser", "Searching - Search For: " + searchForText);

            // Run Search
            SqlCommand dbCommand = new SqlCommand(sql, dbConnection);
            SqlDataReader dbReader = dbCommand.ExecuteReader();

            // Clear old search results from results ArraryList
            results.Clear();

            // Process Results
            if (dbReader.HasRows)
            {
                int currentRecId = 0;
                int currentDiscId = 0;
                Result currentResult = null;

                while (dbReader.Read())
                {
                    int workingRecId = int.Parse(dbReader["recId"].ToString());
                    int workingDiscId = int.Parse(dbReader["discId"].ToString());

                    if (workingRecId != currentRecId)
                    {
                        // Add currentResult to results array
                        if (currentResult != null)
                            results.Add(currentResult);

                        currentRecId = workingRecId;
                        currentResult = new Result();

                        // Look up track listing for current recording
                        string sql2 = "SELECT tracks.trackTitle FROM congregations RIGHT OUTER JOIN recordings RIGHT OUTER JOIN tracks LEFT OUTER JOIN discs ON tracks.trackDisc = discs.discID ON recordings.recId = tracks.trackRec ON congregations.congId = recordings.recCong";
                        sql2 += " WHERE recCong = " + congregation.Id + " AND recId = " + currentRecId;

                        SqlConnection trackListingConnection = SS.Connection();
                        SqlCommand trackListingQuery = new SqlCommand(sql2, trackListingConnection);
                        SqlDataReader trackListingReader = trackListingQuery.ExecuteReader();

                        if (trackListingReader.HasRows) while (trackListingReader.Read())
                                currentResult.AddTrack(trackListingReader["trackTitle"].ToString());

                        trackListingConnection.Close();
                        trackListingConnection.Dispose();

                        // Look up misc information about recording
                        currentResult.Type = (MeetingType)int.Parse(dbReader["recType"].ToString());
                        currentResult.Id = currentRecId;
                        currentResult.Date = DateTime.Parse(dbReader["recDate"].ToString());
                        currentResult.Title = dbReader["recTitle"].ToString();
                    }
                    if (workingDiscId != currentDiscId)
                    {
                        currentDiscId = workingDiscId;
                        currentResult.AddDisc(dbReader["discTitle"].ToString());
                    }
                }

                // Add final currentResult to results array
                results.Add(currentResult);
                Logs.Information("Browser", results.Count + " results found");
            }
            dbReader.Close();
            page = 0;

        }

        void Library_LibraryRecordingDeleted(StoredRecording recording)
        {

        }

        void DisplayResults(int gotoPage)
        {
            ResultsInfo.Content = "Drawing Results";
            ResultsPanel.Children.Clear();
            int numOfResultsThatCanBeDisplayed = (int)Math.Floor(ResultsPanel.ActualHeight / 64);
            if (results.Count > 0)
            {
                if (gotoPage > 0)
                    if ((gotoPage) * numOfResultsThatCanBeDisplayed < results.Count)
                        page = gotoPage;
                    else
                        page = 0;
                else page = 0;
                int offset = page * numOfResultsThatCanBeDisplayed;

                for (int i = 0; i < numOfResultsThatCanBeDisplayed; i++)
                {
                    if (offset + i < results.Count)
                    {
                        ResultControl result = new ResultControl((Result)results[offset + i]);
                        ResultsPanel.Children.Add(result);
                        result.Selected += new ResultControl.ResultSelectedHandler(ShowResult);
                    }
                }
                int displayingTo = 0;
                if ((page + 1) * numOfResultsThatCanBeDisplayed > results.Count) displayingTo = results.Count;
                else displayingTo = (page + 1) * numOfResultsThatCanBeDisplayed;
                ResultsInfo.Content = "displaying " + (page * numOfResultsThatCanBeDisplayed + 1) + "-" + displayingTo + " of " + results.Count + " results";
            }
            else
                ResultsInfo.Content = "no results found";

        }

        void Search()
        {
            if (!resultsWorker.IsBusy & !displayingResults)
            {
                ResultsPanel.Children.Clear();
                RecordingHolder.Content = null;
                ResultsInfo.Content = "Searching";
                resultsWorker.RunWorkerAsync(SearchForTouchBox.Text);
            }
            else
                reSearch = true;
        }

        void CloseCurrentResult()
        {
            if (selectedResult != null) selectedResult.Unselect();
            if (selectedRecording != null) Library.ReturnRecording(selectedRecording);
            RecordingHolder.Content = null;
            WelcomeMessage.Visibility = Visibility.Visible;
        }

        void ShowResult(ResultControl result)
        {
            CloseCurrentResult();
            WelcomeMessage.Visibility = Visibility.Collapsed;
            selectedResult = result;
            selectedRecording = Library.OpenRecording(result.Result.Id);
            RecordingHolder.Content = new RecordingControl(selectedRecording);
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            if (results.Count == 0)
                Search();
        }

        private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            page = 0;
            DisplayResults(page);
        }

        private void NewerButton_Click(object sender, RoutedEventArgs e)
        {
            DisplayResults(page - 1);
        }

        private void OlderButton_Click(object sender, RoutedEventArgs e)
        {
            DisplayResults(page + 1);
        }

        private void SearchForTouchBox_ValueChanged(string _text)
        {
            Search();
        }

        private void BurnButton_Click(object sender, RoutedEventArgs e)
        {
            if (selectedRecording != null)
            {
                AddCDWindow addCDWindow = new AddCDWindow(selectedRecording, max);
                addCDWindow.ShowDialog();
            }
        }

        private void DeleteButton_Click(object sender, RoutedEventArgs e)
        {
            if (SS.AdministratorAuthenticated)
            {
                if (selectedRecording.Locks == 0)
                {
                    if (SSMessageBox.Show("Are you sure?", "Delete this Recording\r\n[" + selectedRecording.Id + "] " + selectedRecording.FormatedDate, SSMessageBoxType.YesNo) == SSMessageBoxResult.Yes)
                    {
                        CloseCurrentResult();

                        Library.DeleteRecording(selectedRecording);

                        if (results.Contains(selectedResult.Result))
                        {
                            results.Remove(selectedResult.Result);
                        }
                        selectedResult = null;
                        selectedRecording = null;
                        DisplayResults(page);
                    }
                }
                else
                {
                    SSMessageBox.Show("Recording locked.", "Error", SSMessageBoxType.Ok);
                }
            }
            else
            {
                SSMessageBox.Show("You must enable Admin mode to delete recordings");
            }
        }

        private void CopyMP3Button_Click(object sender, RoutedEventArgs e)
        {
            if (selectedRecording != null)
            {
                CopyMP3Window copyMP3Window = new CopyMP3Window(selectedRecording);
                copyMP3Window.ShowDialog();
            }
        }
    }
}
